package com.droidski.taskdb.web;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.security.Constraint;
import org.mortbay.jetty.security.ConstraintMapping;
import org.mortbay.jetty.security.HashUserRealm;
import org.mortbay.jetty.security.SecurityHandler;

import com.droidski.taskdb.TaskDB;
import com.droidski.taskdb.cli.CLI;
import com.droidski.taskdb.cli.Main;

public class TaskDBServer {

	CLI cli;
	int port = 8001;
	static TaskDB taskDB;
	FileMonitor monitor;

	public TaskDBServer(CLI cli) throws NumberFormatException {
		this.cli = cli;
		if (cli.args.length > 1) {
			String portStr = cli.args[1];
			port = Integer.parseInt(portStr);
		}
		
	}

	public void start() throws Exception {

		Server server = new Server(port);
		taskDB = TaskDB.load();
		monitor = new FileMonitor(taskDB.getFile(), 1000, new FileListener() {

			@Override
			public void fileModified(File file) {
				try {
					taskDB.reload();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
		});
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				monitor.quit();
			}
		});

		File file = new File("realm.properties");
		
		if (file.isFile()) {
			Constraint constraint = new Constraint();
			constraint.setName(Constraint.__BASIC_AUTH);
			;
			constraint.setRoles(new String[] { "user", "admin" });
			constraint.setAuthenticate(true);

			ConstraintMapping cm = new ConstraintMapping();
			cm.setConstraint(constraint);
			cm.setPathSpec("/*");

			SecurityHandler sh = new SecurityHandler();
			sh.setUserRealm(new HashUserRealm("MyRealm", "realm.properties"));
			sh.setConstraintMappings(new ConstraintMapping[] { cm });

			HandlerCollection handlers = new HandlerCollection();
			handlers.setHandlers(new Handler[] { sh, new HandlerImpl() });
			server.setHandler(handlers);
			Main.out("TaskServer running @ http://localhost:" + port + " ('realm.properties' found - running with authentication ON)");
		} else {
			Main.out("TaskServer running @ http://localhost:" + port + " ('realm.properties' not found - no authentication)");
			server.setHandler(new RestHandler(taskDB));
		}
		server.start();
		monitor.start();

	}

	public class HandlerImpl extends AbstractHandler {
		public void handle(String target, HttpServletRequest request,
				HttpServletResponse response, int dispatch) throws IOException,
				ServletException {
			response.setContentType("text/html");
			response.setStatus(HttpServletResponse.SC_OK);
			response.getWriter().println("<h1>Hello</h1>");
			((Request) request).setHandled(true);
		}
	}
	
	public static interface FileListener {
		public void fileModified(File file);
	}
	
	class FileMonitor {
		
		long lastModified;
		File file;
		boolean isRunning = false;
		Monitor monitor;
		FileListener listener;
		long sleepPeriod;
		
		public FileMonitor(File file, long sleepPeriod, FileListener listener) {
			this.file = file;
			this.lastModified = file.lastModified();
			this.listener = listener;
			this.sleepPeriod = sleepPeriod;
		}
		
		public void start() {
			if ( isRunning() ) return;
			monitor = new Monitor();
			monitor.start();
		}
		
		public boolean isRunning() {
			return isRunning;
		}
		
		public void quit() {
			monitor.interrupt();
		}
		
		class Monitor extends Thread {
			public void run() {
				isRunning = true;
				try {
					while ( true ) {
						if ( file.lastModified() != lastModified ) {
							lastModified = file.lastModified();
							listener.fileModified(file);
						}
						Thread.sleep(sleepPeriod);
					}
				} catch (InterruptedException e) {
				}
				isRunning = false;
			}
		}
	}

}
